"""
OSC Client class
@author : U{ zhangxinlei01<zhangxinlei01@baidu.com>}
@copyright : baidu.com
@date : 2015-11-27
@version : 1.0.0.0
"""
import cStringIO
import copy
import httplib
import os
import json
import logging
import shutil

import baidubce
from baidubce import bce_client_configuration
from baidubce import utils
from baidubce.auth import bce_v1_signer
from baidubce.bce_base_client import BceBaseClient
from baidubce.exception import BceClientError
from baidubce.exception import BceServerError
from baidubce.exception import BceHttpClientError
from baidubce.http import bce_http_client
from baidubce.http import handler
from baidubce.http import http_content_types
from baidubce.http import http_headers
from baidubce.http import http_methods
from baidubce.services import osc
from baidubce.utils import required
from sqlite3.dbapi2 import paramstyle

_logger = logging.getLogger(__name__)
class OscClient(BceBaseClient):
    """
        OSCClient
    """
    def __init__(self, config=None):
        BceBaseClient.__init__(self, config)

    def authorize(self, srcId, targetId, config=None):
        """
        :param srcId:
        :param targetId:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['srcId'] = srcId
        params['targetId'] = targetId
        path = 'v1/thirdparty/osc/authorize' 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.POST, 
            path,
            #body=json.dumps({'password':password}),
            body=None,
            headers=headers,
            params=params,
            config=config)

    def is_authorized(self, srcId, targetId, config=None):
        """
        :param srcId:
        :param targetId:
        :return: 200 for ok, 404 for fail
        """
        params = {}
        params['srcId'] = srcId
        params['targetId'] = targetId
        path = 'v1/thirdparty/osc/authorize' 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def withdraw_authorization(self, srcId, targetId, config=None):
        """
        :param srcId:
        :param targetId:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['srcId'] = srcId
        params['targetId'] = targetId
        path = 'v1/thirdparty/osc/authorize' 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.DELETE, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def create_app(self, userId, appName, appDomain, appType, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app' 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.POST, 
            path,
            body=json.dumps({'appName':appName, 
                 'appDomain':appDomain, 'appType':appType}),
            headers=headers,
            params=params,
            config=config)

    def deploy_app(self, userId, appId, uri, branch, remote, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        params['uri'] = uri
        path = 'v1/thirdparty/osc/app/' + appId 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.PUT, 
            path,
            body=json.dumps({'branch':branch, 'remote':remote}),
            headers=headers,
            params=params,
            config=config)

    def pause_app(self, userId, appId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['pause'] = ''
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app/' + appId
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.PUT, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def start_app(self, userId, appId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['start'] = ''
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app/' + appId 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.PUT, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def delete_app(self, userId, appId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app/' + appId 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.DELETE, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def status_app(self, userId, appId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app/' + appId + '/status' 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def domain_app(self, domain, userId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/domain/' + domain 
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def create_mysql(self, userId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mysql'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.POST, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def getinfo_mysql(self, userId, mysqlId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mysql/' + mysqlId
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def manage_mysql(self, userId, mysqlId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mysql/' + mysqlId + '/manage'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def delete_mysql(self, userId, mysqlId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mysql/' + mysqlId
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.DELETE, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def create_redis(self, userId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/redis'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.POST, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def getinfo_redis(self, userId, redisId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/redis/' + redisId
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def delete_redis(self, userId, redisId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/redis/' + redisId
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.DELETE, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def create_mongo(self, userId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mongo'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.POST, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def getinfo_mongo(self, userId, mongoId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mongo/' + mongoId
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def delete_mongo(self, userId, mongoId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mongo/' + mongoId
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.DELETE, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def manage_mongo(self, userId, mongoId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/mongo/' + mongoId + '/manage'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET,
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def deploy_log(self, userId, appId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        #params['appId'] = appId
        path = 'v1/thirdparty/osc/app/' + appId + '/log/deploy'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    def create_env(self, userId, appId, envName, envValue, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app/' + appId + '/env'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.POST, 
            path,
            body=json.dumps({'envName':envName, 'envValue':envValue}),
            headers=headers,
            params=params,
            config=config)

    def modify_env(self, userId, appId, envName, envValue, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app/' + appId + '/env'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.PUT, 
            path,
            body=json.dumps({'envName':envName, 'envValue':envValue}),
            headers=headers,
            params=params,
            config=config)

    def delete_env(self, userId, appId, envNames, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        params['delete'] = ''
        path = 'v1/thirdparty/osc/app/' + appId + '/env'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.PUT, 
            path,
            body=json.dumps({'envNames':envNames}),
            headers=headers,
            params=params,
            config=config)

    def get_envs(self, userId, appId, config=None):
        """
        :param userId:
        :param appName:
        :param appDomain:
        :param appType:
        :param appRole:
        :return: 200 for ok, 500 for fail
        """
        params = {}
        params['userId'] = userId
        path = 'v1/thirdparty/osc/app/' + appId + '/env'
        headers = {}
        headers[http_headers.CONTENT_TYPE] = http_content_types.JSON
        return self._send_request(
            http_methods.GET, 
            path,
            body=None,
            headers=headers,
            params=params,
            config=config)

    @staticmethod
    def _parse_osc_resp(http_response, response):
        """Sets response.body to http_response and response.user_metadata to a dict consists of all http
        headers starts with 'x-bce-meta-'.

        :param http_response: the http_response object returned by HTTPConnection.getresponse()
        :type http_response: httplib.HTTPResponse

        :param response: general response object which will be returned to the caller
        :type response: baidubce.BceResponse

        :return: always true
        :rtype bool
        """
        body = http_response.read()
        if body:
            response.__dict__.update(
                    json.loads(body, object_hook=utils.dict_to_python_object).__dict__)
        response.__setattr__("http_status", http_response.status)
        response.__setattr__("http_reason", http_response.reason)
        response.__setattr__("http_headers", http_response.getheaders())
        http_response.close()
        return True

    @staticmethod
    def _merge_config(self, config):
        if config is None:
            return self.config
        else:
            new_config = copy.copy(self.config)
            new_config.merge_non_none_values(config)
            return new_config
        
    def _send_request(
           self, http_method, path,
           body=None, headers=None, params=None,
           config=None,
           body_parser=None):
        config = self._merge_config(self, config)
        if body_parser is None:
            #body_parser = handler.parse_json
            body_parser = OscClient._parse_osc_resp
    
        return bce_http_client.send_request(
            #config, bce_v1_signer.sign, [handler.parse_error, body_parser],
            config, bce_v1_signer.sign, [body_parser],
            http_method, osc.URL_PREFIX + path, body, headers, params)
